using System;
using System.Collections.Generic;
using JKFrame;
using Map.config;
using UnityEngine;

public class MapManager : MonoBehaviour
{
    // 地图尺寸
    public int mapSize; // 一行或者一列有多少个地图块
    public int mapChunkSize; // 一个地图块有多少个格子
    public float cellSize; // 一个格子多少米

    // 地图的随机参数
    public float noiseLacunarity; // 噪音间隙
    public int mapSeed; // 地图种子
    public int spawnSeed; // 随时地图对象的种子
    public float marshLimit; // 沼泽的边界

    // 地图的美术资源
    public Material mapMaterial;
    public Texture2D forestTexutre;
    public Texture2D[] marshTextures;
    public MapConfig mapConfig; //地图配置

    private MapGenerator mapGenerator;
    public int viewDinstance; // 玩家可视距离，单位是Chunk
    public Transform viewer; // 观察者
    private Vector3 lastViewerPos = Vector3.one * -1;
    public Dictionary<Vector2Int, MapChunkController> mapChunkDic; // 全部已有的地图块
    public float updateChunkTime = 1f;
    private bool canUpdateChunk = true;
    private float chunkSizeOnWord; // 在世界中实际的 地图块 尺寸 单位米
    private List<MapChunkController> lastVisibleChunkList = new List<MapChunkController>();


    private void Start()
    {
        //初始化地图生成器
        mapGenerator = new MapGenerator(mapSize, mapChunkSize, cellSize, mapMaterial, noiseLacunarity, mapSeed,
            spawnSeed,
            marshLimit, forestTexutre, marshTextures, mapConfig);
        mapGenerator.GenerateMapData();
        mapChunkDic = new Dictionary<Vector2Int, MapChunkController>();
        chunkSizeOnWord = mapChunkSize * cellSize;
    }

    private void Update()
    {
        UpdataVisableChunk();
        
        
    }

    /// <summary>
    /// 根据观察者（玩家）所在的位置来确定那些地图块可见
    /// </summary>
    private void UpdataVisableChunk()
    {
        //检查观察者是否移动
        if (viewer.position == lastViewerPos) return;
        lastViewerPos = viewer.position;
        //检查是否允许更新
        if (canUpdateChunk == false) return;
        //获取观察者所在当前地图块
        var currChunkIndex = GetMapChunkIndexFromWorldPos(viewer.position);
        // JKLog.Log("Player Chunk Index: " + currChunkIndex);
        //先循环地图块 关闭不需要显示的地图块
        for (int i = lastVisibleChunkList.Count - 1; i >= 0; i--)
        {
            // JKLog.Log("lastVisibleChunkList  Index: " + lastVisibleChunkList[i].ChunkIndex.ToString());
            var chunkIndex = lastVisibleChunkList[i].ChunkIndex;
            if (Mathf.Abs(chunkIndex.x - currChunkIndex.x) > viewDinstance ||
                Mathf.Abs(chunkIndex.y - currChunkIndex.y) > viewDinstance)
            {
                lastVisibleChunkList[i].SetActive(false);
                lastVisibleChunkList.RemoveAt(i);
            }
        }
        

        //开始生成显示的地图
        int startX = currChunkIndex.x - viewDinstance;
        int startY = currChunkIndex.y - viewDinstance;
        for (int x = 0; x < viewDinstance * 2 + 1; x++)
        {
            for (int y = 0; y < viewDinstance * 2 + 1; y++)
            {
                canUpdateChunk = false;
                Invoke("ResetCanUpdateChunkFlag", updateChunkTime);
                var chunkIndexTmp = new Vector2Int(startX + x, startY + y);
                //判断之前是否已经加载过
                if (mapChunkDic.TryGetValue(chunkIndexTmp, out MapChunkController chunk))
                {
                    //判断之前显示的地图块中是否包含这个地图块
                    if (!lastVisibleChunkList.Contains(chunk))
                    {
                        //没有包含的话 添加 + 激活
                        lastVisibleChunkList.Add(chunk);
                        chunk.SetActive(true);
                    }
                }
                //之前没有加载过
                else
                {
                    //新生成地图块
                    chunk = GenerateMapChunk(chunkIndexTmp);
                    if (chunk != null)
                    {
                        chunk.SetActive(true);
                        lastVisibleChunkList.Add(chunk);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 根据世界坐标获取当前所在地图块的索引
    /// </summary>
    /// <param name="worldPos"></param>
    /// <returns></returns>
    private Vector2Int GetMapChunkIndexFromWorldPos(Vector3 worldPos)
    {
        //TODO 计算有问题？
        // int x = Mathf.Clamp(Mathf.RoundToInt(worldPos.x / mapChunkSize / cellSize), 1, mapSize);
        // int y = Mathf.Clamp(Mathf.RoundToInt(worldPos.z / mapChunkSize / cellSize), 1, mapSize);
        int x = Mathf.Clamp(Mathf.FloorToInt(worldPos.x / mapChunkSize / cellSize) , 0, mapSize);
        int y = Mathf.Clamp(Mathf.FloorToInt(worldPos.z / mapChunkSize / cellSize) , 0, mapSize);

        return new Vector2Int(x, y);
    }

    /// <summary>
    /// 根据索引创建指定的地图块
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private MapChunkController GenerateMapChunk(Vector2Int index)
    {
        if (index.x >= mapSize || index.y >= mapSize || index.x < 0 || index.y < 0) return null;
        MapChunkController chunkController = mapGenerator.GenerateMapChunk(index, transform);
        mapChunkDic.Add(index, chunkController);
        return chunkController;
    }

    private void ResetCanUpdateChunkFlag()
    {
        canUpdateChunk = true;
    }
}